package com.tl.satoken.service;

import com.tl.satoken.domain.entity.*;
import jakarta.annotation.PostConstruct;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

@Service
public class RoomService {
    private static final Logger log = LoggerFactory.getLogger(RoomService.class);

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    public RoomService() {
    }

    @PostConstruct
    public void init() {
        this.cleanupOldData();
    }

    private void cleanupOldData() {
        try {
            log.info("清理旧的游戏数据...");
            Set<String> keys = this.redisTemplate.keys("game:*");
            if (keys != null && !keys.isEmpty()) {
                this.redisTemplate.delete(keys);
                log.info("清理了 {} 个旧的游戏数据", keys.size());
            }
            
            log.info("清理旧的金币数据...");
            Set<String> coinKeys = this.redisTemplate.keys("coin:*");
            if (coinKeys != null && !coinKeys.isEmpty()) {
                this.redisTemplate.delete(coinKeys);
                log.info("清理了 {} 个旧的金币数据", coinKeys.size());
            }
            
            Set<String> roomCoinKeys = this.redisTemplate.keys("room:coins:*");
            if (roomCoinKeys != null && !roomCoinKeys.isEmpty()) {
                this.redisTemplate.delete(roomCoinKeys);
                log.info("清理了 {} 个房间金币数据", roomCoinKeys.size());
            }
            
            Set<String> roomCoinPositionKeys = this.redisTemplate.keys("room:coin_position:*");
            if (roomCoinPositionKeys != null && !roomCoinPositionKeys.isEmpty()) {
                this.redisTemplate.delete(roomCoinPositionKeys);
                log.info("清理了 {} 个房间金币位置数据", roomCoinPositionKeys.size());
            }
        } catch (Exception e) {
            log.warn("清理旧数据时出现异常: {}", e.getMessage());
        }
    }

    public RoomJoinResult joinRoom(Player player) {
        try {
            // 检查同一个英雄是否已经登录
            String heroKey = "game:hero:" + player.getHeroId();
            if (Boolean.TRUE.equals(this.redisTemplate.hasKey(heroKey))) {
                return new RoomJoinResult(false, "同一个英雄不能同时登陆", null);
            }

            String targetRoomId = this.findAvailableRoom();
            if (targetRoomId == null) {
                targetRoomId = this.createNewRoom();
                log.info("创建新房间: {}", targetRoomId);
            }

            String roomKey = "game:room:" + targetRoomId;
            
            // 使用原子操作检查并添加，避免竞态条件
            Long addResult = this.redisTemplate.opsForSet().add(roomKey, player.getHeroId());
            if (addResult == 0) {
                // 玩家已经存在于房间中
                return new RoomJoinResult(false, "玩家已在房间中", targetRoomId);
            }
            
            // 检查添加后房间人数是否超过限制
            Long roomSize = this.redisTemplate.opsForSet().size(roomKey);
            if (roomSize != null && roomSize > 2L) {
                // 如果超过限制，移除刚添加的玩家
                this.redisTemplate.opsForSet().remove(roomKey, player.getHeroId());
                return new RoomJoinResult(false, "房间已满", null);
            }

            player.setPosition(player.getPosition());
            player.setRoomId(targetRoomId);
            this.redisTemplate.opsForValue().set(heroKey, targetRoomId);
            
            String playerHashKey = "game:player:" + player.getHeroId() + ":data";
            Map<String, Object> playerData = new HashMap<>();

            // 基本字段
            playerData.put("id", player.getId());
            playerData.put("heroId", player.getHeroId());
            playerData.put("animation", player.getAnimation());
            playerData.put("roomId", player.getRoomId());
            playerData.put("sessionId", player.getSessionId());

            // 位置信息
            Position position = player.getPosition();
            if (position != null) {
                Map<String, Float> positionMap = new HashMap<>();
                positionMap.put("x", position.getX());
                positionMap.put("y", position.getY());
                positionMap.put("z", position.getZ());
                playerData.put("position", positionMap);
            }

            // 旋转信息
            Rotation rotation = player.getRotation();
            if (rotation != null) {
                Map<String, Float> rotationMap = new HashMap<>();
                rotationMap.put("y", rotation.getY());
                playerData.put("rotation", rotationMap);
            }

            // 一次性存储所有Hash字段
            this.redisTemplate.opsForHash().putAll(playerHashKey, playerData);
            
            log.info("玩家 {} 成功加入房间 {}, 当前房间人数: {}", player.getUsername(), targetRoomId, this.getRoomPlayerCount(targetRoomId));
            return new RoomJoinResult(true, "加入成功", targetRoomId);
            
        } catch (Exception e) {
            log.error("加入房间时出现异常: {}", e.getMessage(), e);
            return new RoomJoinResult(false, "加入房间失败: " + e.getMessage(), null);
        }
    }

    public boolean leaveRoom(Integer heroId) {
        try {
            String playerKey = "game:hero:" + heroId;
            String roomId = (String)this.redisTemplate.opsForValue().get(playerKey);
            if (roomId == null) {
                return false;
            }
            
            String roomKey = "game:room:" + roomId;
            
            this.redisTemplate.opsForSet().remove(roomKey, heroId);
            
            // 获取heroId并删除heroKey
            String playerHashKey = "game:player:" + heroId + ":data";
            Object heroIdObj = this.redisTemplate.opsForHash().get(playerHashKey, "heroId");
            if (heroIdObj != null) {
                String heroKey = "game:hero:" + heroIdObj;
                this.redisTemplate.delete(heroKey);
            }
            
            this.redisTemplate.delete(playerKey);
            this.redisTemplate.delete(playerHashKey);
            
            log.info("玩家 {} 离开房间 {}, 剩余人数: {}", heroId, roomId, this.getRoomPlayerCount(roomId));
            
            if (this.getRoomPlayerCount(roomId) == 0) {
                this.redisTemplate.delete(roomKey);
                log.info("房间 {} 已清空，删除房间", roomId);
            }

            return true;
        } catch (Exception e) {
            log.error("离开房间时出现异常: {}", e.getMessage(), e);
            return false;
        }
    }

    public List<Player> getPlayersInRoom(String roomId) {
        try {
            String roomKey = "game:room:" + roomId;

            Set<Object> playerIds = this.redisTemplate.opsForSet().members(roomKey);
            if (playerIds == null || playerIds.isEmpty()) {
                return new ArrayList<>();
            }

            List<Player> playerList = new ArrayList<>();

            for (Object obj : playerIds) {
                if (obj instanceof Integer playerId) {
                    Player player = getPlayerById(playerId);
                    if (player != null) {
                        playerList.add(player);
                    }
                }
            }

            return playerList;
        } catch (Exception e) {
            log.error("获取房间玩家时出现异常: {}", e.getMessage(), e);
            return new ArrayList<>();
        }
    }
    
    private Player getPlayerById(Integer playerId) {
        try {
            String playerHashKey = "game:player:" + playerId + ":data";
            
            Map<Object, Object> playerData = this.redisTemplate.opsForHash().entries(playerHashKey);
            if (playerData.isEmpty()) {
                return null;
            }

            Player player = new Player();

            // 设置sessionId
            if (playerData.get("sessionId") != null) {
                player.setSessionId((String) playerData.get("sessionId"));
            }
            // 设置heroId
            if (playerData.get("heroId") != null) {
                player.setHeroId((Integer) playerData.get("heroId"));
            }
            
            // 设置position
            if (playerData.get("position") != null) {
                try {
                    @SuppressWarnings("unchecked")
                    Map<String, Float> positionMap = (Map<String, Float>) playerData.get("position");
                    Float x = positionMap.get("x");
                    Float y = positionMap.get("y");
                    Float z = positionMap.get("z");
                    if (x != null && y != null) {
                        player.setPosition(new Position(x, y, z != null ? z : 0.0f));
                    }
                } catch (Exception e) {
                    log.warn("无法解析位置信息: {}", playerData.get("position"));
                }
            }
            
            // 设置rotation
            if (playerData.get("rotation") != null) {
                try {
                    @SuppressWarnings("unchecked")
                    Map<String, Float> rotationMap = (Map<String, Float>) playerData.get("rotation");
                    Float y = rotationMap.get("y");
                    if (y != null) {
                        Rotation rotation = new Rotation();
                        rotation.setY(y);
                        player.setRotation(rotation);
                    }
                } catch (Exception e) {
                    log.warn("无法解析旋转信息: {}", playerData.get("rotation"));
                }
            }
            
            // 设置animation
            if (playerData.get("animation") != null) {
                player.setAnimation((String) playerData.get("animation"));
            }
            
            return player;
        } catch (Exception e) {
            log.error("获取玩家数据时出现异常: {}", e.getMessage(), e);
            return null;
        }
    }

    public int getRoomPlayerCount(String roomId) {
        try {
            String roomKey = "game:room:" + roomId;
            Long size = this.redisTemplate.opsForSet().size(roomKey);
            return size != null ? size.intValue() : 0;
        } catch (Exception e) {
            log.error("获取房间人数时出现异常: {}", e.getMessage(), e);
            return 0;
        }
    }

    public List<RoomInfo> getAllRooms() {
        try {
            List<RoomInfo> roomInfos = new ArrayList();
            Set<String> keys = this.redisTemplate.keys("game:room:*");
            if (keys != null) {
                for(String key : keys) {
                    if (!key.endsWith(":counter")) {
                        String roomId = key.substring("game:room:".length());
                        if (!"counter".equals(roomId)) {
                            RoomInfo roomInfo = this.getRoomInfo(roomId);
                            if (roomInfo != null) {
                                roomInfos.add(roomInfo);
                            }
                        }
                    }
                }
            }

            return roomInfos;
        } catch (Exception e) {
            log.error("获取所有房间时出现异常: {}", e.getMessage(), e);
            return new ArrayList();
        }
    }

    public RoomInfo getRoomInfo(String roomId) {
        try {
            int playerCount = this.getRoomPlayerCount(roomId);
            if (playerCount < 0) {
                return null;
            } else {
                return new RoomInfo(roomId, playerCount, 2);
            }
        } catch (Exception e) {
            log.error("获取房间信息时出现异常: {}", e.getMessage(), e);
            return null;
        }
    }

    public boolean updatePlayerPosition(Integer heroId, Player updatedPlayer) {
        try {
            String playerKey = "game:hero:" + heroId;
            String roomId = (String)this.redisTemplate.opsForValue().get(playerKey);
            if (roomId == null) {
                return false;
            }
            
            String roomKey = "game:room:" + roomId;
            
            Boolean isMember = this.redisTemplate.opsForSet().isMember(roomKey, heroId);
            if (!Boolean.TRUE.equals(isMember)) {
                log.warn("玩家 {} 不在房间 {} 中，无法更新位置", heroId, roomId);
                return false;
            }
            
            String playerHashKey = "game:player:" + heroId + ":data";
            
            // 只更新有用的字段：position, rotation, animation
            Position pos = updatedPlayer.getPosition();
            if (pos != null) {
                Map<String, Float> positionMap = new HashMap<>();
                positionMap.put("x", pos.getX());
                positionMap.put("y", pos.getY());
                positionMap.put("z", pos.getZ());
                this.redisTemplate.opsForHash().put(playerHashKey, "position", positionMap);
            }
            
            // 更新旋转信息
            Rotation rotation = updatedPlayer.getRotation();
            if (rotation != null) {
                Map<String, Float> rotationMap = new HashMap<>();
                rotationMap.put("y", rotation.getY());
                this.redisTemplate.opsForHash().put(playerHashKey, "rotation", rotationMap);
            }
            
            // 更新动画信息
            if (updatedPlayer.getAnimation() != null) {
                this.redisTemplate.opsForHash().put(playerHashKey, "animation", updatedPlayer.getAnimation());
            }
            
            
            return true;
        } catch (Exception e) {
            log.error("更新玩家位置时出现异常: {}", e.getMessage(), e);
            return false;
        }
    }

    private String findAvailableRoom() {
        try {
            Set<String> keys = this.redisTemplate.keys("game:room:*");
            String targetRoomId = null;
            int maxPlayers = 0;
            if (keys != null) {
                for(String key : keys) {
                    if (key.endsWith(":counter")) {
                        continue;
                    }
                    
                    String roomId = key.substring("game:room:".length());
                    if (!"counter".equals(roomId)) {
                        int playerCount = this.getRoomPlayerCount(roomId);
                        if (playerCount < 2 && playerCount >= maxPlayers) {
                            maxPlayers = playerCount;
                            targetRoomId = roomId;
                        }
                    }
                }
            }

            return targetRoomId;
        } catch (Exception e) {
            log.error("寻找可用房间时出现异常: {}", e.getMessage(), e);
            return null;
        }
    }

    private String createNewRoom() {
        try {
            if (!Boolean.TRUE.equals(this.redisTemplate.hasKey("game:room:counter"))) {
                this.redisTemplate.opsForValue().set("game:room:counter", 0L);
            }

            Long roomNumber = this.redisTemplate.opsForValue().increment("game:room:counter");
            String roomId = "Room_" + roomNumber;
            String roomKey = "game:room:" + roomId;
            
            this.redisTemplate.expire(roomKey, 3L, TimeUnit.DAYS);
            return roomId;
        } catch (Exception e) {
            log.error("创建新房间时出现异常: {}", e.getMessage(), e);
            return "Room_" + System.currentTimeMillis();
        }
    }

    public int getActiveConnections() {
        try {
            Set<String> keys = this.redisTemplate.keys("game:room:*");
            if (keys == null) {
                return 0;
            } else {
                int totalConnections = 0;

                for(String key : keys) {
                    if (!key.equals("game:room:counter")) {
                        Long size = this.redisTemplate.opsForSet().size(key);
                        if (size != null) {
                            totalConnections += size.intValue();
                        }
                    }
                }

                return totalConnections;
            }
        } catch (Exception e) {
            log.error("获取活跃连接数时出现异常: {}", e.getMessage(), e);
            return 0;
        }
    }

    public int getTotalPlayers() {
        try {
            Set<String> keys = this.redisTemplate.keys("game:room:*");
            if (keys == null) {
                return 0;
            } else {
                int totalPlayers = 0;

                for(String key : keys) {
                    if (!key.equals("game:room:counter")) {
                        Long size = this.redisTemplate.opsForSet().size(key);
                        if (size != null) {
                            totalPlayers += size.intValue();
                        }
                    }
                }

                return totalPlayers;
            }
        } catch (Exception e) {
            log.error("获取总玩家数时出现异常: {}", e.getMessage(), e);
            return 0;
        }
    }

    public List<Map<String, Object>> getRoomCoins(String roomId) {
        try {
            String roomCoinsKey = "room:coins:" + roomId;
            
            Set<Object> coinIds = this.redisTemplate.opsForSet().members(roomCoinsKey);
            if (coinIds == null || coinIds.isEmpty()) {
                return new ArrayList<>();
            }
            
            List<Map<String, Object>> coins = new ArrayList<>();
            for (Object coinId : coinIds) {
                String coinKey = "coin:" + coinId;
                Map<Object, Object> coinData = this.redisTemplate.opsForHash().entries(coinKey);
                
                if (!coinData.isEmpty()) {
                    // 检查heroId字段是否为空（未被抢走）
                    String heroId = (String) coinData.get("heroId");
                    if (heroId == null || heroId.trim().isEmpty()) {
                        Map<String, Object> coin = new HashMap<>();
                        coin.put("id", coinId);
                        coin.put("position", coinData.get("position"));
                        coins.add(coin);
                    }
                }
            }
            
            return coins;
        } catch (Exception e) {
            log.error("获取房间 {} 金币数据失败", roomId, e);
            return new ArrayList<>();
        }
    }

}
